package internal

import (
	"errors"
	"k9-panel/app/model"
	"k9-panel/app/query"
	"k9-panel/app/service/dto"
	"k9-panel/app/service/dto/convert"
	"strings"
)

func StringToConfig(content string) ([]*model.BaseConfig, error) {
	var (
		batch []*model.BaseConfig
	)
	configs := strings.Split(strings.TrimSpace(content), "\n")
	for idx, config := range configs {
		if strings.HasPrefix(config, "##") {
			continue
		}
		conf := strings.TrimSpace(config)
		if len(conf) == 0 {
			continue
		}
		if strings.HasPrefix(config, "#") {
			conf += "=1"
		}
		configPair := strings.Split(conf, "=")
		if len(configPair) < 2 {
			return nil, errors.New("配置格式异常,附近位置:" + config)
		}
		baseConfig := &model.BaseConfig{}
		baseConfig.Key = configPair[0]
		baseConfig.Value = strings.Join(configPair[1:], "=")
		baseConfig.Sort = idx
		batch = append(batch, baseConfig)
	}
	return batch, nil
}
func ConfigToString(textConfig *strings.Builder, configs []*model.BaseConfig) (content string, err error) {
	for _, v := range configs {
		textConfig.WriteString(v.Key + "=" + v.Value + "\n")
	}
	return textConfig.String(), nil
}

type BaseConfigService struct {
}

func (receiver *BaseConfigService) Convert2ConfigEnv(name string, configs []*model.BaseConfig) (*dto.ConfigEnv, error) {
	//TODO implement me
	return convert.BaseConfig2ConfigEnv(name, configs), nil

}

func (receiver *BaseConfigService) GetListByProject(id uint) ([]*model.BaseConfig, error) {
	return query.BaseConfig.Where(query.BaseConfig.ProjectId.Eq(int(id))).Find()
}

func (receiver *BaseConfigService) Delete(model *model.BaseConfig) (uint, error) {
	res, err := query.BaseConfig.Where(query.BaseConfig.Key.Eq(model.Key)).Delete()
	if err != nil {
		return 0, err
	}
	return uint(res.RowsAffected), nil
}

func (receiver *BaseConfigService) DeleteByProject(id int) (int64, error) {
	res, err := query.BaseConfig.Where(query.BaseConfig.ProjectId.Eq(int(id))).Delete()

	if err != nil {
		return 0, err
	}
	return res.RowsAffected, nil
}
func (receiver *BaseConfigService) GetByProject(id uint) (*dto.ProjectBaseConfigInfo, error) {
	res, err := query.BaseConfig.Where(query.BaseConfig.ProjectId.Eq(int(id))).
		Order(query.BaseConfig.Sort.Asc()).Find()
	if err != nil {
		return nil, err
	}
	info := &dto.ProjectBaseConfigInfo{}
	project := model.Project{}
	project.ID = id
	p, err := svc.Project.Get(&project)
	if err != nil {
		return nil, err
	}
	info.Project = &dto.ProjectData{Id: p.ID, Name: p.Name}
	configText := strings.Builder{}
	info.Content, _ = ConfigToString(&configText, res)
	return info, nil
}
func (receiver *BaseConfigService) Update(projectId uint, content string) (uint, error) {
	var (
		deletes []uint
		updates []*model.BaseConfig
		addList []*model.BaseConfig
	)
	dbResp, err := query.BaseConfig.Where(query.BaseConfig.ProjectId.Eq(int(projectId))).
		Order(query.BaseConfig.Sort.Asc()).Find()
	if err != nil {
		return 0, err
	}
	cfg, err := convert.StringToConfigEnv(content)
	updateFilter := make(map[string]string, len(cfg.Items))
	dbFilter := make(map[string]interface{}, len(dbResp))

	if err != nil {
		return 0, err
	}
	for _, config := range cfg.Items {
		updateFilter[config.Key] = config.Value
	}

	for _, resItem := range dbResp {
		dbFilter[resItem.Key] = resItem.Value
		if _, ok := updateFilter[resItem.Key]; ok {
			if updateFilter[resItem.Key] != resItem.Value {
				resItem.Value = updateFilter[resItem.Key]
				updates = append(updates, resItem)
			}
		} else {
			deletes = append(deletes, resItem.ID)
		}
	}
	for _, update := range cfg.Items {
		if dbFilter[update.Key] == nil {
			model1 := &model.BaseConfig{}
			model1.Key = update.Key
			model1.Value = update.Value
			model1.ProjectId = int(projectId)
			model1.Sort = update.Sort
			addList = append(addList, model1)
		}
	}

	err = query.BaseConfig.Create(addList...)
	if err != nil {
		return 0, err
	}
	if len(deletes) > 0 {
		_, err = query.BaseConfig.Where(query.BaseConfig.ID.In(deletes...)).Delete()
		if err != nil {
			return 0, err
		}
	}

	for _, updateItem := range updates {
		_, err := query.BaseConfig.Where(query.BaseConfig.ID.Eq(updateItem.ID)).Update(query.BaseConfig.Value, updateItem.Value)
		if err != nil {
			return 0, err
		}
	}
	return 1, nil
}
